#ifndef  HELPER_OBJECT_STANDARDHASH_H
#define  HELPER_OBJECT_STANDARDHASH_H

#include <string>
#include <unordered_map>

#include "helper/object/RawType.h" // String, Pointer, .....
#include "helper/object/Iterator.h"
#include "helper/object/Hash.h"

namespace helper {
namespace object {

class String;
class Pointer;
class Array;
class StandardHash : public Hash {
public:
    StandardHash();
    ~StandardHash() override;

    size_t size() const override;

    bool containsKey(const std::string & key) const override;


    std::pair<bool, const char> getChar(const Pair::first_type & key) const override;
    std::pair<bool, const int> getInt(const Pair::first_type & key) const override;
    std::pair<bool, const long long> getLongLong(const Pair::first_type & key) const override;
    std::pair<bool, const double> getDouble(const Pair::first_type & key) const override;

    std::pair<bool,std::string> getStdString(const Pair::first_type & key) const override;

    String * getString(const Pair::first_type & key) const override;
    Array * getArray(const Pair::first_type & key) const override;
    Hash * getHash(const Pair::first_type & key) const override;

    std::pair<bool, void *> getPointer(const Pair::first_type & key) const override;
    int insertPointer(const Pair::first_type & key, const void * ptr) override;

    int insert(const Pair::first_type & key, const char ch) override;
    int insert(const Pair::first_type & key, const int i) override;
    int insert(const Pair::first_type & key, const long long ll) override;
    int insert(const Pair::first_type & key, const double dbl) override;

    int insert(const Pair::first_type & key, const char * str) override;
    int insert(const Pair::first_type & key, const char * buffer , size_t len)override;
    int insert(const Pair::first_type & key, const char * buffer , size_t offset, size_t len) override;
    int insert(const Pair::first_type & key, size_t n, char ch) override;

    int insert(const std::string & key, const std::string & value) override;



public:
    int insert(const std::string & key, const Hash::Pair::second_type &o) override;

    Hash::Pair::second_type remove(const Hash::Pair::first_type & key) override;

    const Hash::Pair::second_type * get(const std::string  & key) const override;
    Hash::Pair::second_type set(const Hash::Pair::first_type & key, Hash::Pair::second_type & value) override;

    std::shared_ptr<Iterator<Hash::Pair>> iterator() const override;

    std::string toString() const override;
    bool equals(const Object & obj) const override;
    Object * copy() const override;

    void clear() override;

protected:
    friend class StandardHashIterator;  
    void freeHolderResource(); 
private:
    typedef std::unordered_map<std::string, Object *> HashImp;
    HashImp hash;
};

class StandardHashIterator : public Iterator<Hash::Pair> {
public:
    explicit StandardHashIterator(Hash & hash);
    explicit StandardHashIterator(const Hash & hash);
    ~StandardHashIterator() override;

    bool hasNext() const override;
    const ElementType & next() override;

private:
    const Hash & hashRef;
    StandardHash::HashImp::iterator iter;
    StandardHash::HashImp::iterator end;
};

} // end of namespace object
} // end of namespace helper

#endif   /* HELPER_OBJECT_STANDARDHASH_H */
